package com.elasticcloudservice.predict;

import com.filetool.main.Main;
import com.filetool.util.CloneUtils;
import com.filetool.util.FileUtil;

import java.text.ParseException;
import java.util.*;

/**
 * @Author: Chy
 * @Description: 模拟退火 + FF
 * @Date: Created at 15:38 2018/3/11
 */
public class AllocateOverRunTime {

    public static String[] allocate(String[] inputContent, String[] predict) throws ParseException {


        //获取输入文件中的虚拟机信息
        Map<String, VirtualMachine> vmMap = getVmMapFromInput(inputContent);

        //获取输入文件种所有服务器信息
        List<ElasticCloudServer> allEcs = getEcsListFromInput(inputContent);

        //使用的服务器集合
        List<ElasticCloudServer> ecsList = new ArrayList<ElasticCloudServer>();

        //将预测结果解析成虚拟机的集合
        List<VirtualMachine> predictVmList = getVmListFromPredict(predict, vmMap);

//        System.out.println("-------------------" + Main.i + "号用例-----------------" );//提交时把代码注释掉
        //将预测出的虚拟机装入服务器
        int[] totalVmInfo = setVmInEcsByFFDAndSA(predictVmList, vmMap, ecsList, allEcs);

        //微调
        Collections.sort(predictVmList, new VmComparator()); //对predictVmList进行排序
        Collections.sort(ecsList, new EcsComparator()); //对ecsList按照资源使用率从小到大排序
//        totalVmInfo = adjustDF(ecsList, vmMap, predictVmList, predict, totalVmInfo);

        //提交时把以下代码注释掉
        System.out.println("服务器数量：" + ecsList.size());
        double useRate = calUseRate(ecsList, totalVmInfo, allEcs);
        System.out.println("使用率：" + useRate);
        int count = 0;
        for(ElasticCloudServer ecs: ecsList){
            if (count >= 10){
                System.out.println();
                count = 0;
            }
            System.out.printf(" %1f, " ,ecs.getUseRate());
            System.out.printf(" cpu: %1f", (ecs.getCPUs() * 1.0 / ecs.getOriginCPU()));
            System.out.printf(" mem: %1f",(ecs.getMems() * 1.0 / ecs.getOriginMem()));
            count++;
        }
        String[] testData = FileUtil.read("files/testData/Testcase" + Main.i + ".txt", null); //测试文件
        double predictAccuracy = calPredictAccuracyRate(vmMap, predict, testData);
        System.out.println("预测准确率：" + predictAccuracy);
        System.out.println("得分：" + predictAccuracy * useRate * 100);


        //输出结果
        return getResult(ecsList, totalVmInfo, predict, allEcs);

    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 获取输入文件中所有服务器的信息
     * @Date: 19:27 2018/4/20
     */
    private static List<ElasticCloudServer> getEcsListFromInput(String[] inputContent) {
        List<ElasticCloudServer> ecsList = new ArrayList<>();

        int ecsTypes = Integer.parseInt(inputContent[0]);  //服务器种类数

        for (int i = 1; i < 1 + ecsTypes; i++) {
            String[] splitArray = inputContent[i].split(" ");
            String ecsName = splitArray[0];
            int ecsCPU = Integer.parseInt(splitArray[1]);
            int ecsMem = Integer.parseInt(splitArray[2]);
            ElasticCloudServer ecs = new ElasticCloudServer(ecsName, ecsCPU, ecsMem);
            ecsList.add(ecs);
        }

        return ecsList;
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 模拟退火 + FF实现装箱
     * @Date: 19:26 2018/4/7
     */
    private static int[] setVmInEcsByFFDAndSA(List<VirtualMachine> predictVmList, Map<String, VirtualMachine> vmMap,
                                              List<ElasticCloudServer> ecsList, List<ElasticCloudServer> allEcs) {
        int totalVmCPU = 0; //虚拟机总的CPU核心数
        int totalVmMems = 0; //虚拟机总的内存
        int totalVmNum = predictVmList.size(); //虚拟机总数

        //虚拟机资源计算
        for (VirtualMachine vm: predictVmList) {
            totalVmCPU += vm.getCPUs();
            totalVmMems += vm.getMems() / 1024;
        }
        long startTime = System.currentTimeMillis();

        //二分循环，把使用率低的服务器拆解出来重新跑一遍
        int iteration = 3;
        while (iteration >= 0){
            List<ElasticCloudServer> tmpBestEcsList = setVmSA(predictVmList, vmMap, allEcs, startTime);
            List<VirtualMachine> leftVmList = new ArrayList<>();
            if (iteration > 0 && (System.currentTimeMillis() - startTime) / 1000 < 60){
                for (ElasticCloudServer ecs: tmpBestEcsList){
                    if (ecs.getUseRate() >= 0.985){
                        ecsList.add(ecs);
                    }else {
                        for (String vmLeft: ecs.getVmList()){
                            leftVmList.add(vmMap.get(vmLeft));
                        }
                    }
                }
            }else {
                for (ElasticCloudServer ecs: tmpBestEcsList){
                    ecsList.add(ecs);
                }
                break;
            }
            iteration--;
            predictVmList = leftVmList;
        }


/*        //随机序列
        List<Integer> dice = new ArrayList<>();  //随机序列
        for (int i = 0; i < totalVmNum; i++) {
            dice.add(i);
        }

        List<ElasticCloudServer> bestEcsList = new ArrayList<>();  //最优的服务器集合

        //模拟退火参数
        double T = 0.5;  //初始温度
        double TEnd = 0.00001; //终止温度
        double delta = 0.999; //温度下降率
        double minFunction = Double.MAX_VALUE;  //评价函数值

        while (T > TEnd) {
            Collections.shuffle(dice);  //洗牌
            List<ElasticCloudServer> ecsListTemp = new ArrayList<>();
            //随机交换两个虚拟机
            int first = dice.get(0), second = dice.get(1);
            swap(predictVmList, first, second);
            //遍历预测结果集,进行一次装箱操作
            for (VirtualMachine vm : predictVmList) {
                //获取每台虚拟机的名称、CPU、内存
                int vmCPU = vm.getCPUs();
                int vmMems = vm.getMems() / 1024; //MB转换为GB
                String vmName = vm.getName();

                //装箱
                binPacking(ecsListTemp, vmName, vmCPU, vmMems, allEcs);
            }

            //计算评价函数，若小于当前最小值，则直接传入，否则以一定概率替换。
            double funcValue = calFunc(ecsListTemp, vmMap, allEcs); //计算评价函数
            if (funcValue < minFunction) {
                bestEcsList = ecsListTemp;
                minFunction = funcValue;
            } else {
                // 以一定概率替换
                double p = (Math.exp((minFunction - funcValue) / (T)));
                if (Math.random() < p) {
                    bestEcsList = ecsListTemp;
                    minFunction = funcValue;
                } else {
                    swap(predictVmList, first, second);
                }
            }
            T *= delta;
        }

        //将不满足使用率标准的箱子中的vm取出，重新分配装箱
        //将以满足使用率的箱子存储起来
        List<VirtualMachine> leftVmList = new ArrayList<>();
        for (ElasticCloudServer ecs: bestEcsList){
            if (ecs.getUseRate() >= 0.985){
                ecsList.add(ecs);
            }else {
                for (String vmLeft: ecs.getVmList()){
                    leftVmList.add(vmMap.get(vmLeft));
                }
            }
        }

        List<ElasticCloudServer> tmpBestEcsList = setVmSA(leftVmList, vmMap, allEcs);

        for (ElasticCloudServer ecs : tmpBestEcsList) {
            ecsList.add(ecs);
        }*/

        int[] result = new int[]{totalVmCPU, totalVmMems, totalVmNum};

        return result;
    }

    private static List<ElasticCloudServer> setVmSA(List<VirtualMachine> leftVmList, Map<String, VirtualMachine> vmMap, List<ElasticCloudServer> allEcs, long startTime) {
        List<ElasticCloudServer> bestEcsList = new ArrayList<>();  //最优的服务器集合
        int totalVmNum = leftVmList.size();
        //随机序列
        List<Integer> dice = new ArrayList<>();  //随机序列
        for (int i = 0; i < totalVmNum; i++) {
            dice.add(i);
        }
        //模拟退火参数
        double T = 0.5;  //初始温度
        double TEnd = 0.00001; //终止温度
        double delta = 0.999; //温度下降率
        double minFunction = Double.MAX_VALUE;  //评价函数值

        while (T > TEnd ) {
            Collections.shuffle(dice);  //洗牌
            List<ElasticCloudServer> ecsListTemp = new ArrayList<>();
            //随机交换两个虚拟机
            int first = dice.get(0), second = dice.get(1);
            swap(leftVmList, first, second);
            //遍历预测结果集,进行一次装箱操作
            for (VirtualMachine vm : leftVmList) {
                //获取每台虚拟机的名称、CPU、内存
                int vmCPU = vm.getCPUs();
                int vmMems = vm.getMems() / 1024; //MB转换为GB
                String vmName = vm.getName();

                //装箱
                binPacking(ecsListTemp, vmName, vmCPU, vmMems, allEcs);
            }

            //计算评价函数，若小于当前最小值，则直接传入，否则以一定概率替换。
            double funcValue = calFunc(ecsListTemp, vmMap, allEcs); //计算评价函数
            if (funcValue < minFunction) {
                bestEcsList = ecsListTemp;
                minFunction = funcValue;
            } else {
                // 以一定概率替换
                double p = (Math.exp((minFunction - funcValue) / (T)));
                if (Math.random() < p) {
                    bestEcsList = ecsListTemp;
                    minFunction = funcValue;
                } else {
                    swap(leftVmList, first, second);
                }
            }
            T *= delta;
        }
        return bestEcsList;
    }


    /**
     * @Author: Chy
     * @Param:
     * @Description: 交换集合的两个元素
     * @Date: 15:38 2018/4/13
     */
    private static void swap(List<VirtualMachine> predictVmList, int first, int second) {
        VirtualMachine temp = predictVmList.get(first);
        predictVmList.set(first, predictVmList.get(second));
        predictVmList.set(second, temp);
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 微调预测结果
     * @Date: 23:30 2018/4/7
     */
    private static int[] adjustDF(List<ElasticCloudServer> ecsList, Map<String, VirtualMachine> vmMap, List<VirtualMachine> predictVmList, String[] predict, int[] totalVmInfo) {

        int totalVmCPU = totalVmInfo[0], totalVmMems = totalVmInfo[1], totalVmNum = totalVmInfo[2];
        int k = 0;
        Iterator iterator = ecsList.iterator();
        while (iterator.hasNext()) {
            k++;
            ElasticCloudServer ecs = (ElasticCloudServer) iterator.next();
            if (ecs.getVmList().size() <= 2) {
                System.out.println("服务器" + k + "只装了少于2台的虚拟机");
                for (String name : ecs.getVmList()) {
                    for (int i = 0; i < predict.length; i++) {
                        String[] split = predict[i].split(" ");
                        if (split[0].equals(name)) {
                            predict[i] = name + " " + (Integer.parseInt(split[1]) - 1);
                            totalVmNum--;
                            totalVmCPU -= vmMap.get(name).getCPUs();
                            totalVmMems -= vmMap.get(name).getMems() / 1024;
                        }
                    }
                }
                iterator.remove();
            } else {
                for (VirtualMachine vm : predictVmList) {
                    String vmName = vm.getName();
                    int vmCPU = vmMap.get(vmName).getCPUs();
                    int vmMems = vmMap.get(vmName).getMems() / 1024; //MB转换为GB

                    if (ecs.getCPUs() >= 2 * vmCPU && ecs.getMems() >= 2 * vmMems) {
                        System.out.println("服务器" + k + "还能装下2台" + vmName);
                        ecs.add(vm);
                        ecs.add(vm);
//                        ecs.getVirtualMachines().add(vm);
//                        ecs.getVirtualMachines().add(vm);
                        totalVmCPU += vmCPU * 2;  //虚拟机总资源相应增加
                        totalVmMems += vmMems * 2;
                        for (int i = 0; i < predict.length; i++) {
                            String[] split = predict[i].split(" ");
                            if (split[0].equals(vmName)) {
                                predict[i] = vmName + " " + (Integer.parseInt(split[1]) + 2);
                                totalVmNum += 2;
                            }
                        }
                    }

//                    while (ecs.getCPUs() >= vmCPU && ecs.getMems() >= vmMems) {
//                        System.out.println("服务器" + k + "还能装下" + vmName);
//                        ecs.getVmList().add(vmName);  //把最大的虚拟机装进服务器
//                        ecs.getVirtualMachines().add(vm);
//                        ecs.setCPUs(ecs.getCPUs() - vmCPU); //服务器资源相应减少
//                        ecs.setMems(ecs.getMems() - vmMems); //服务器资源相应减少
//                        for (int i = 0; i < predict.length; i++) {
//                            String[] split = predict[i].split(" ");
//                            if (split[0].equals(vmName)) {
//                                predict[i] = vmName + " " + (Integer.parseInt(split[1]) + 1);
//                                totalVmNum += 1;
//                                totalVmCPU += vmCPU;  //虚拟机总资源相应增加
//                                totalVmMems += vmMems;
//                            }
//                        }
//                    }
                }
            }
        }
        return new int[]{totalVmCPU, totalVmMems, totalVmNum};
    }


    /**
     * @Author: Chy
     * @Param:
     * @Description: 计算模拟退火的评价函数值
     * @Date: 20:27 2018/4/7
     */
    private static double calFunc(List<ElasticCloudServer> ecsListTemp, Map<String, VirtualMachine> vmMap, List<ElasticCloudServer> allEcs){
        //评价函数1
//        double value = 0;
//        for (ElasticCloudServer ecs : ecsListTemp) {
//            int temp = 0;
//            for (String vmName : ecs.getVmList()) {
//                int vmCPU = vmMap.get(vmName).getCPUs();
//                int vmMem = vmMap.get(vmName).getMems() / 1024;
//                if (target.equals("CPU")) {
//                    temp += vmCPU;
//                } else {
//                    temp += vmMem;
//                }
//            }
//            value += temp * temp;
//        }
//
//        return value;

        //评价函数2
//        double sum = 0;
//        double fitness, filled, capacity;
//        double k = 2;
//
//        for (int i = 0; i < ecsListTemp.size(); i++) {
//            if (target.equals("CPU")) {
//                filled = ecsInfo[0] - ecsListTemp.get(i).getCPUs();
//                capacity = ecsInfo[0];
//            } else {
//                filled = ecsInfo[1] - ecsListTemp.get(i).getMems();
//                capacity = ecsInfo[1];
//            }
//            sum += Math.pow(filled / capacity, k);
//        }
//
//        fitness = sum / ecsListTemp.size();
//
//        return fitness;

        //评价函数3
        double value1 = .0;
        double value2 = .0;
        double fitness = .0;

        double totalEcsCPU = .0;  //服务器总CPU
        double totalEcsMem = .0;  //服务器总MEM
        double ecsLeftCPU = .0;  //服务器剩余CPU
        double ecsLeftMem = .0;  //服务器剩余MEM
        for (ElasticCloudServer ecs : ecsListTemp){
            ecsLeftCPU += ecs.getCPUs();
            ecsLeftMem += ecs.getMems();
            if (ecs.getName().equals(allEcs.get(0).getName())){
                totalEcsCPU += allEcs.get(0).getCPUs();
                totalEcsMem += allEcs.get(0).getMems();
            }else if (ecs.getName().equals(allEcs.get(1).getName())){
                totalEcsCPU += allEcs.get(1).getCPUs();
                totalEcsMem += allEcs.get(1).getMems();
            }else if (ecs.getName().equals(allEcs.get(2).getName())){
                totalEcsCPU += allEcs.get(2).getCPUs();
                totalEcsMem += allEcs.get(2).getMems();
            }
        }

        value1 = ecsLeftCPU / totalEcsCPU;
        value2 = ecsLeftMem / totalEcsMem;
        fitness = (value1 + value2) / 2;

        return fitness;
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 改进版的FF装箱
     * @Date: 20:19 2018/4/7
     */
    private static void binPacking(List<ElasticCloudServer> ecsListTemp, String vmName, int vmCPU, int vmMems, List<ElasticCloudServer> allEcs) {
        double generalRatio = allEcs.get(0).getMems() * 1.0 / allEcs.get(0).getCPUs();  //General类型服务器的mem/cpu值
        double largeMemoryRatio = allEcs.get(1).getMems() * 1.0 / allEcs.get(1).getCPUs();  //Large-Memory类型服务器的mem/cpu值
        double highPerformanceRatio = allEcs.get(2).getMems() * 1.0 / allEcs.get(2).getCPUs();  //High-Performance类型服务器的mem/cpu值
        double vmRatio = vmMems * 1.0 / vmCPU;

        boolean isContained = false;
        double minLeftRatio = Double.MAX_VALUE;
        int count = 0;
        int find = 0;
        for (ElasticCloudServer ecs : ecsListTemp) {
            //找到ecs剩余mem/cpu 与当前需要加入的vm最匹配的
            double tmpRatio = Math.abs(ecs.getMemDivCPU() - (vmMems * 1.0 / vmCPU));
            if (vmCPU <= ecs.getCPUs() && vmMems <= ecs.getMems() && tmpRatio <= minLeftRatio) {
                if(tmpRatio == minLeftRatio){
//                    if ((ecs.getMems() - vmMems) * 1.0 / (ecs.getCPUs() - vmCPU))
                }else {
                    find = count;
                    minLeftRatio = tmpRatio;
                }
                isContained = true;
            }
            count++;
        }
        if (isContained){
            ElasticCloudServer ecs = ecsListTemp.get(find);
            ecs.getVmList().add(vmName);  //将虚拟机配置到服务器中
            ecs.setCPUs(ecs.getCPUs() - vmCPU); //服务器资源相应减少
            ecs.setMems(ecs.getMems() - vmMems);
            ecs.setMemDivCPU(ecs.getMems() * 1.0 / ecs.getCPUs());
        }

        //若所有服务器都装不下该虚拟机，则新建一台服务器
        if (!isContained) {
            //根据MEM / CPU的值判断虚拟机最适合开辟哪个服务器
            double genAndVmDiff = Math.abs(generalRatio - vmRatio);
            double largeAndVmDiff = Math.abs(largeMemoryRatio - vmRatio);
            double highAndVmDiff = Math.abs(highPerformanceRatio - vmRatio);
            double min1 = (genAndVmDiff < largeAndVmDiff) ? genAndVmDiff : largeAndVmDiff;
            min1 = (min1 < highAndVmDiff) ? min1 : highAndVmDiff;
            int newIndex = 0;
            for (int i = 0; i < allEcs.size(); i++){
                if (min1 == genAndVmDiff)
                    newIndex = 0;
                else if (min1 == largeAndVmDiff)
                    newIndex = 1;
                else if (min1 == highAndVmDiff)
                    newIndex = 2;
            }
            ElasticCloudServer ecs = CloneUtils.clone(allEcs.get(newIndex));
            ecs.getVmList().add(vmName);
            ecs.setCPUs(ecs.getCPUs() - vmCPU); //服务器资源相应减少
            ecs.setMems(ecs.getMems() - vmMems);
            ecs.setMemDivCPU(ecs.getMems() * 1.0 / ecs.getCPUs());
            isContained = true;
            ecsListTemp.add(ecs);
        }

        //重新调整,把资源使用率小的服务器中的虚拟机挪到其他服务器中
//        Collections.sort(ecsListTemp, new EcsComparator());
        for (ElasticCloudServer ecs : ecsListTemp)
            ecs.setUseRate(ecs.getUseRate());

    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 获取虚拟机的种类，并存入Map集合
     * @Date: 13:55 2018/3/10
     */
    private static Map<String, VirtualMachine> getVmMapFromInput(String[] inputContent) {
        Map<String, VirtualMachine> vmMap = new HashMap<>();
        int ecsTypes = Integer.parseInt(inputContent[0]);  //服务器种类数
        int flavorTypes = Integer.parseInt(inputContent[2 + ecsTypes]);   //虚拟机种类数

        for (int i = 3 + ecsTypes; i < 3 + ecsTypes + flavorTypes; i++) {
            String[] splitArray = inputContent[i].split(" ");
            VirtualMachine vm = new VirtualMachine();
            vm.setName(splitArray[0]);
            vm.setCPUs(Integer.parseInt(splitArray[1]));
            vm.setMems(Integer.parseInt(splitArray[2]));
            vmMap.put(splitArray[0], vm);
        }

        return vmMap;
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 将预测结果解析成虚拟机集合
     * @Date: 18:12 2018/3/10
     */
    private static List<VirtualMachine> getVmListFromPredict(String[] predict, Map<String, VirtualMachine> vmMap) {

        //将预测结果解析到一个List<Map<String,VirtualMachine>>中
        List<VirtualMachine> predictVmList = new ArrayList<>();
        for (String predictEntryStr : predict) {
            String[] split = predictEntryStr.split(" ");
            for (int i = 0; i < Integer.parseInt(split[1]); i++) {
                VirtualMachine vm = vmMap.get(split[0]);
                predictVmList.add(vm);
            }
        }
        //对sortedPredictVmList进行排序
        Collections.sort(predictVmList, new VmComparator());
//        Collections.shuffle(predictVmList);
        return predictVmList;
    }


    /**
     * @Author: Chy
     * @Param:
     * @Description: 输出最终结果
     * @Date: 11:59 2018/3/10
     */
    public static String[] getResult(List<ElasticCloudServer> ecsList, int[] totalVmInfo, String[] predictResult, List<ElasticCloudServer> allEcs) {
        int ecsNum = ecsList.size();  //服务器数量
        int generalNum = 0, largeMemoryNum = 0, highPerformanceNum = 0;
        String general = "General";
        String largeMemory = "Large-Memory";
        String highPerformance = "High-Performance";
        List<ElasticCloudServer> generalServer = new ArrayList<>();
        List<ElasticCloudServer> largeMemoryServer = new ArrayList<>();
        List<ElasticCloudServer> highPerformanceServer = new ArrayList<>();

        List<String> resultList = new ArrayList<>();
        resultList.add(totalVmInfo[2] + "");  //虚拟机总数量
        //各种虚拟机的数量
        for (int i = 0; i < predictResult.length; i++) {
            resultList.add(predictResult[i]);
        }
        resultList.add("");  //虚拟机数量后的空行

        //统计各类型的服务器数量
        for (ElasticCloudServer ecs : ecsList){
            if (ecs.getName().equals(general)) {
                generalNum++;
                generalServer.add(ecs);
            }
            else if (ecs.getName().equals(largeMemory)){
                largeMemoryNum++;
                largeMemoryServer.add(ecs);
            }
            else if (ecs.getName().equals(highPerformance)) {
                highPerformanceNum++;
                highPerformanceServer.add(ecs);
            }
        }

        //获取general类型的服务器里的虚拟机信息
        if (generalNum != 0){
            resultList.add(general + " " + generalNum);
            int i = 1;
            for (ElasticCloudServer ecs : generalServer){
                List<String> vmList = ecs.getVmList();
                //统计每个服务器内放置的虚拟机信息
                Set<String> vmSet = new HashSet<>(vmList);
                StringBuffer sb = new StringBuffer();
                sb.append(general + "-" + i + " ");
                for (String vmName : vmSet) {
                    sb.append(vmName + " " + Collections.frequency(vmList, vmName) + " ");
                }
                resultList.add(sb.toString().trim());
                i++;
            }
        }

        //获取Large-Memory类型的服务器里的虚拟机信息
        if (largeMemoryNum != 0){
            resultList.add("");
            resultList.add(largeMemory + " " + largeMemoryNum);
            int i = 1;
            for (ElasticCloudServer ecs : largeMemoryServer){
                List<String> vmList = ecs.getVmList();
                //统计每个服务器内放置的虚拟机信息
                Set<String> vmSet = new HashSet<>(vmList);
                StringBuffer sb = new StringBuffer();
                sb.append(largeMemory + "-" + i + " ");
                for (String vmName : vmSet) {
                    sb.append(vmName + " " + Collections.frequency(vmList, vmName) + " ");
                }
                resultList.add(sb.toString().trim());
                i++;
            }
        }

        //获取High-Performance类型的服务器里的虚拟机信息
        if (highPerformanceNum != 0){
            resultList.add("");
            resultList.add(highPerformance + " " + highPerformanceNum);
            int i = 1;
            for (ElasticCloudServer ecs : highPerformanceServer){
                List<String> vmList = ecs.getVmList();
                //统计每个服务器内放置的虚拟机信息
                Set<String> vmSet = new HashSet<>(vmList);
                StringBuffer sb = new StringBuffer();
                sb.append(highPerformance + "-" + i + " ");
                for (String vmName : vmSet) {
                    sb.append(vmName + " " + Collections.frequency(vmList, vmName) + " ");
                }
                resultList.add(sb.toString().trim());
                i++;
            }
        }

        String[] result = new String[resultList.size()];
        int i = 0;
        for (String str : resultList)
            result[i++] = str;
        return result;
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 自定义的服务器比较器
     * @Date: 17:41 2018/3/23
     */
    private static class EcsComparator implements Comparator<ElasticCloudServer> {

        @Override
        public int compare(ElasticCloudServer ecs1, ElasticCloudServer ecs2) {
            double ecs1UseRate = ecs1.getUseRate();  //ecs1资源使用率
            double ecs2UseRate = ecs2.getUseRate();  //ecs2资源使用率

            return ecs1UseRate > ecs2UseRate ? 1 : (ecs1UseRate < ecs2UseRate ? -1 : 0);
        }
    }

    /**
     * @Author: Chy
     * @Description: 自定义的虚拟机比较器
     * @Date: 23:34 2018/3/10
     */
    private static class VmComparator implements Comparator<VirtualMachine> {

        @Override
        public int compare(VirtualMachine map1, VirtualMachine map2) {

            if (map1.getCPUs() > map2.getCPUs()){
                return -1;
            }else if (map1.getCPUs() <  map2.getCPUs()){
                return  1;
            }else {
                if (map1.getMems() > map2.getMems()){
                    return -1;
                }else if (map1.getMems() < map2.getMems()){
                    return 1;
                }else {
                    return 0;
                }
            }

        }
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 计算资源使用率
     * @Date: 17:34 2018/3/10
     */
    private static double calUseRate(List<ElasticCloudServer> ecsList, int[] totalVmInfo, List<ElasticCloudServer> allEcs) {
        int ecsNum = ecsList.size();  //服务器数量
        int totalEcsCPU = 0;    //服务器总CPU核心数
        int totalEcsMem = 0;   //服务器总内存
        double useRate = 0.0;   //资源使用率

        //计算服务器总资源
        for (ElasticCloudServer ecs : ecsList){
            if (ecs.getName().equals(allEcs.get(0).getName())){
                totalEcsCPU += allEcs.get(0).getCPUs();
                totalEcsMem += allEcs.get(0).getMems();
            }else if (ecs.getName().equals(allEcs.get(1).getName())){
                totalEcsCPU += allEcs.get(1).getCPUs();
                totalEcsMem += allEcs.get(1).getMems();
            }else if (ecs.getName().equals(allEcs.get(2).getName())){
                totalEcsCPU += allEcs.get(2).getCPUs();
                totalEcsMem += allEcs.get(2).getMems();
            }
        }

        useRate =  (totalVmInfo[0] * 1.0 / totalEcsCPU + totalVmInfo[1] * 1.0 / totalEcsMem) / 2;
        return useRate;
    }

    /**
     * @Author: Chy
     * @Param:
     * @Description: 计算预测准确率
     * @Date: 15:00 2018/3/11
     */
    private static double calPredictAccuracyRate(Map<String, VirtualMachine> vmMap, String[] predict, String[] testData) {
        //1.获取测试数据里，各种flavor的数量
        List<String> nameList = new ArrayList<>();
        for (int i = 0; i < testData.length; i++) {
            nameList.add(testData[i].split("\t")[1]);
        }
        Set<String> tempSet = new HashSet<>(nameList);
        Map<String, Integer> realCountMap = new HashMap<>();
        for (String vmName : tempSet) {
            realCountMap.put(vmName, Collections.frequency(nameList, vmName));
        }
        //2.计算预测准确率
        int sumOfRealQuadratic = 0;  //分母里实际结果的平方和
        int sumOfPredictQuadratic = 0;  //分母里预测结果的平方和
        int sumOfDiffQuadratic = 0;  //分子里差的平方和
        for (String predictStr : predict) {
            String vmNameOfPredict = predictStr.split(" ")[0];
            int vmNumsOfPredict = Integer.parseInt(predictStr.split(" ")[1]);  //预测的数量
            int vmNumsOfReal = realCountMap.get(vmNameOfPredict) == null ? 0 : realCountMap.get(vmNameOfPredict); //实际的数量
            System.out.println(vmNameOfPredict + " 预测：" + vmNumsOfPredict + " 真实：" + vmNumsOfReal);
            sumOfRealQuadratic += vmNumsOfReal * vmNumsOfReal;
            sumOfPredictQuadratic += vmNumsOfPredict * vmNumsOfPredict;
            sumOfDiffQuadratic += (vmNumsOfReal - vmNumsOfPredict) * (vmNumsOfReal - vmNumsOfPredict);
        }

        double numerator = Math.sqrt(sumOfDiffQuadratic * 1.0 / vmMap.size()); //分子
        double denominator = Math.sqrt(sumOfRealQuadratic * 1.0 / vmMap.size()) + Math.sqrt(sumOfPredictQuadratic * 1.0 / vmMap.size()); //分母
        double accuracy = 1 - numerator / denominator;

        return accuracy;
    }
}

